/**
 * Copyright (C) 2011 Andrew C. Love (DNC) <dnc.app.sup@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dnc.cloak.service;

import java.util.List;

import javax.security.auth.Subject;

import org.apache.log4j.Logger;

import com.dnc.cloak.framework.CloakException;
import com.dnc.cloak.framework.context.Context;
import com.dnc.cloak.framework.context.ContextFactory;
import com.dnc.cloak.framework.persistence.CrudResult;
import com.dnc.cloak.framework.persistence.gen.SecRestriction;
import com.dnc.cloak.framework.persistence.gen.SecUser;
import com.dnc.cloak.framework.persistence.gen.SecUserExample;
import com.dnc.cloak.framework.persistence.gen.SecUserRole;
import com.dnc.cloak.framework.persistence.gen.SecUserRoleExample;
import com.dnc.cloak.framework.security.CloakPrincipal;
import com.dnc.cloak.framework.security.SecurityException;
import com.dnc.cloak.framework.service.ServiceException;
import com.dnc.cloak.service.gen.LogService;
import com.dnc.cloak.service.gen.SecRestrictionTypeService;
import com.dnc.cloak.service.gen.SecRoleRestrictionService;
import com.dnc.cloak.service.gen.SecRoleService;
import com.dnc.cloak.service.gen.SecUserRoleService;
import com.dnc.cloak.service.gen.SecUserService;
import com.dnc.cloak.service.genext.SecRestrictionServiceExtension;

public class SecurityServiceImpl implements SecurityService {

    private LogService logService;
    private SecUserService secUserService;
    private SecRestrictionServiceExtension secRestrictionService;
    private SecRestrictionTypeService secRestrictionTypeService;
    private SecRoleService secRoleService;
    private SecRoleRestrictionService secRoleRestrictionService;
    private SecUserRoleService secUserRoleService;
    
    private static final Logger logger = Logger.getLogger(SecurityServiceImpl.class.getName());
    
    @Override
    public Context login(String securityPolicy, String user, String credential) throws SecurityException, ServiceException {
        Context context;
        
        SecUserExample example = new SecUserExample();
        com.dnc.cloak.framework.persistence.gen.SecUserExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user);
        criteria.andCredentialEqualTo(credential);

        CrudResult<SecUser> result = secUserService.crud(null, null, example);
        
        if (result.getNumSelect()>0) {
            SecUser secUser = result.getResult().get(0);
            CloakPrincipal principal = new CloakPrincipal();
            principal.setName(user);
            principal.setPassword(credential);
            principal.setAuthenticated(true);
            principal.setLstUptTime(secUser.getLstUptTime());
            principal.setLstUptUser(secUser.getLstUptUser());
            
            Subject subject = new Subject();
            subject.getPrincipals().add(principal);
            
            try {
                context = ContextFactory.createContext(subject);
            }
            catch (CloakException e) {
                throw new SecurityException(SecurityException.Type.OTHER,e);
            }            
            
            return context;
        }
        else {
            throw new SecurityException(SecurityException.Type.USER_OR_PASSWORD_INVALID);
        }
        
    }
 
    @Override
    public Subject login(Context context, String securityPolicy, String user, String credential) throws SecurityException, ServiceException {
        SecUserExample example = new SecUserExample();
        com.dnc.cloak.framework.persistence.gen.SecUserExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user);
        criteria.andCredentialEqualTo(credential);

        CrudResult<SecUser> result = secUserService.crud(context, null, example);
        
        if (result.getNumSelect()>0) {
            SecUser secUser = result.getResult().get(0);
            CloakPrincipal principal = new CloakPrincipal();
            principal.setName(user);
            principal.setPassword(credential);
            principal.setAuthenticated(true);
            principal.setLstUptTime(secUser.getLstUptTime());
            principal.setLstUptUser(secUser.getLstUptUser());
            
            Subject subject = new Subject();
            subject.getPrincipals().add(principal);
            
            return subject;
        }
        else {
            throw new SecurityException(SecurityException.Type.USER_OR_PASSWORD_INVALID);
        }
        
    }
    
    
    
    @Override
    public Context createContext(String securityPolicy, Subject subject) throws SecurityException, ServiceException {
        Context context = null;
        
        try {
            context = ContextFactory.createContext(subject);
        }
        catch (CloakException e) {
            throw new SecurityException(SecurityException.Type.OTHER,e);
        }            
        
        return context;
    }

    @Override
    public boolean isValid(Context context, String user, String credential) throws SecurityException, ServiceException {
        SecUserExample example = new SecUserExample();
        com.dnc.cloak.framework.persistence.gen.SecUserExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user);
        criteria.andCredentialEqualTo(credential);

        CrudResult<SecUser> result = secUserService.crud(context, null, example);
        
        if (result.getNumSelect()>0) {
            return true;
        }
        else {
            return false;
        }
    }    
    
    @Override
    public boolean isAuthorized(Context context, CloakPrincipal user, String roleId) throws SecurityException, ServiceException {
        SecUserRoleExample example = new SecUserRoleExample();
        com.dnc.cloak.framework.persistence.gen.SecUserRoleExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user.getName());
        criteria.andRoleIdEqualTo(roleId);
        
        CrudResult<SecUserRole> result = secUserRoleService.crud(context, null, example);
         
        if (result.getNumSelect()>0) {
            return true;
        }
        else {
            return false;    
        }    
    }
    
    @Override
    public boolean hasRole(Context context, CloakPrincipal user, String roleId) throws SecurityException, ServiceException {
        SecUserRoleExample example = new SecUserRoleExample();
        com.dnc.cloak.framework.persistence.gen.SecUserRoleExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user.getName());
        criteria.andRoleIdEqualTo(roleId);
        
        CrudResult<SecUserRole> result = secUserRoleService.crud(context, null, example);
         
        if (result.getNumSelect()>0) {
            return true;
        }
        else {
            return false;    
        }    
    }

    @Override
    public List<SecUserRole> getRoles(Context context, CloakPrincipal user) throws SecurityException, ServiceException {
        SecUserRoleExample example = new SecUserRoleExample();
        com.dnc.cloak.framework.persistence.gen.SecUserRoleExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(user.getName());
        
        CrudResult<SecUserRole> result = secUserRoleService.crud(context, null, example);

        return result.getResult();
    }
    
    @Override
    public List<SecRestriction> getRestrictions(Context context, CloakPrincipal user) throws SecurityException, ServiceException {

        return secRestrictionService.selectRestrictionByUser(context, user);
        
    }
  
    @Override
    public List<SecRestriction> getRestrictionsByType(Context context,CloakPrincipal principal, String restrictionType) throws SecurityException, ServiceException {
        return secRestrictionService.selectRestrictionsByType(context, principal, restrictionType);
    }   

    public SecUserService getSecUserService() {
        return secUserService;
    }
    public void setSecUserService(SecUserService secUserService) {
        this.secUserService = secUserService;
    }
    public LogService getLogService() {
        return logService;
    }
    public void setLogService(LogService logService) {
        this.logService = logService;
    }
    public SecRestrictionServiceExtension getSecRestrictionService() {
        return secRestrictionService;
    }
    public void setSecRestrictionService(SecRestrictionServiceExtension secRestrictionService) {
        this.secRestrictionService = secRestrictionService;
    }
    public SecRestrictionTypeService getSecRestrictionTypeService() {
        return secRestrictionTypeService;
    }
    public void setSecRestrictionTypeService(
            SecRestrictionTypeService secRestrictionTypeService) {
        this.secRestrictionTypeService = secRestrictionTypeService;
    }
    public SecRoleService getSecRoleService() {
        return secRoleService;
    }
    public void setSecRoleService(SecRoleService secRoleService) {
        this.secRoleService = secRoleService;
    }
    public SecRoleRestrictionService getSecRoleRestrictionService() {
        return secRoleRestrictionService;
    }
    public void setSecRoleRestrictionService(
            SecRoleRestrictionService secRoleRestrictionService) {
        this.secRoleRestrictionService = secRoleRestrictionService;
    }
    public SecUserRoleService getSecUserRoleService() {
        return secUserRoleService;
    }
    public void setSecUserRoleService(SecUserRoleService secUserRoleService) {
        this.secUserRoleService = secUserRoleService;
    }

    @Override
    public CloakPrincipal getCloakPrincipal(Subject subject) {
        CloakPrincipal[] principals = subject.getPrincipals().toArray(new CloakPrincipal[subject.getPrincipals().size()]);

        for (int i = 0; i < principals.length; i++) {
            logger.info(principals[i].getName());            
        }
        if (principals.length > 0) {
            return principals[0];            
        }
        else{
            return null;
        }        
    }      
  
}
